// 
//  Copyright (C) 2009 Jacek Trubłajewicz
// 
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//  
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// 

using System;
using System.Drawing;
using System.Threading;
using Mono.Unix;
using NLog;

namespace wxGadu
{

	/// <summary>
	/// Represents window for notify user about
	/// new incoming chat and contact status change
	/// </summary>
	public class NotifyWindow : wx.MiniFrame
	{
		/// <summary>
		/// Used for invoking async life cycle method
		/// </summary>
		public delegate void WindowLifeCycle();
		
		#region Id
		public enum Id
		{
		
		}
		#endregion
		
		#region sizers
		private wx.BoxSizer topSizer;
		private wx.BoxSizer boxSizer;
		private wx.BoxSizer textSizer;
		#endregion
		
		#region controls
		private wx.StaticBitmap avatarBitmap;
		private wx.StaticText headerST;
		private wx.TextCtrl nameTC;
		#endregion
		
		#region data members
		private MainFrame mainFrame;
		private string header;
		private string name;
		private wx.Bitmap avatar;
		private int ttl;
		// indicates that window should be closed
		private bool close;
		#endregion
		
		private Mutex closeMutex;
#if LOG
		private Logger logger = LogManager.GetCurrentClassLogger();
#endif
		
		/// <summary>
		/// Ctor
		/// </summary>
		/// <param name="parent">
		/// A <see cref="wx.Window"/>
		/// </param>
		/// <param name="id">
		/// A <see cref="System.Int32"/>
		/// </param>
		/// <param name="header">
		/// A <see cref="System.String"/>
		/// header message, this can be "[new chat]" or
		/// "[status chaged]"
		/// </param>
		/// <param name="name">
		/// A <see cref="System.String"/>
		/// contact name
		/// </param>
		/// <param name="avatar">
		/// A <see cref="wx.Bitmap"/>
		/// Contact photo/avatar
		/// </param>
		/// <param name="ttl">
		/// A <see cref="System.Int32"/>
		/// time before window will be automaticaly
		/// closed
		/// </param>
		/// <param name="pos">
		/// A <see cref="Point"/>
		/// position on the screen
		/// </param>
		public NotifyWindow(wx.Window parent, int id, string header, string name, wx.Bitmap avatar, int ttl, Point pos):
			base(parent, id, name, pos, wx.Window.wxDefaultSize, 
			     wx.MiniFrame.wxSTAY_ON_TOP|wx.Frame.wxCLOSE_BOX)
		{
#if LOG
			logger.Trace(String.Format(Catalog.GetString("Opening notify window: {0}"), name));
#endif
			mainFrame = (MainFrame) parent;
			this.header = header;
			this.name = name;
			this.avatar = avatar;
			this.ttl = ttl;
			
			close = false;
			closeMutex = new Mutex();
			
			DoControls();
			DoControlsProperties();
			DoLayout();
			
			EVT_LEFT_DOWN(new wx.EventListener(FrameCloseAsyncRequest));
			EVT_CLOSE(new wx.EventListener(OnFrameClose));
			EVT_UPDATE_UI((int) FakeId.closeNewChatNotify, new wx.EventListener(FrameCloseAsyncRequest));
			
			// invoke async life cycle method
			WindowLifeCycle lifeCycleAsync = new WindowLifeCycle(LifeCycle);
			lifeCycleAsync.BeginInvoke(null, null);
		}
		
		private void DoControls()
		{
			avatarBitmap = new wx.StaticBitmap(this, wx.Window.wxID_ANY, avatar,
			                                   wx.Window.wxDefaultPosition, new Size(96, 96));
			headerST = new wx.StaticText(this, header);
			nameTC = new wx.TextCtrl(this, wx.Window.wxID_ANY, name,
			                         wx.Window.wxDefaultPosition, wx.Window.wxDefaultSize,
			                         wx.TextCtrl.wxTE_CENTER|wx.TextCtrl.wxTE_MULTILINE|
			                         wx.TextCtrl.wxNO_BORDER);
		}
		
		private void DoControlsProperties()
		{
			wx.Font hfont = wx.SystemSettings.GetFont(wx.SystemFont.wxSYS_DEFAULT_GUI_FONT);
			hfont.PointSize += 3;
//			hfont.Weight = wx.FontWeight.wxBOLD;
//			hfont.Underlined = true;
			
			wx.Font nfont = wx.SystemSettings.GetFont(wx.SystemFont.wxSYS_DEFAULT_GUI_FONT);
			nfont.PointSize += 1;
			
			headerST.Font = hfont;
			nameTC.BackgroundColour = this.BackgroundColour;
			nameTC.Enable(false);
			nameTC.Font = nfont;
		}
		
		private void DoLayout()
		{
			topSizer = new wx.BoxSizer(wx.Orientation.wxVERTICAL);
			{
				boxSizer = new wx.BoxSizer(wx.Orientation.wxHORIZONTAL);
				{
					boxSizer.Add(avatarBitmap, 0, 0);
					boxSizer.Add(10, 20, 0, 0, 0);
					
					textSizer = new wx.BoxSizer(wx.Orientation.wxVERTICAL);
					{
						textSizer.Add(headerST, 0, wx.Direction.wxBOTTOM|wx.Alignment.wxALIGN_CENTER_HORIZONTAL, 5);
						textSizer.Add(nameTC, 0, wx.Alignment.wxALIGN_CENTER_HORIZONTAL);
					}
					boxSizer.Add(textSizer, 0, 0);
					
					boxSizer.Add(10, 20, 0, 0, 0);
				}
				topSizer.Add(boxSizer, 0, wx.Direction.wxALL, 5);
			}
			this.Sizer = topSizer;
			topSizer.Fit(this);
			topSizer.SetSizeHints(this);
		}
		
		private void OnFrameClose(object sender, wx.Event evt)
		{
			closeMutex.WaitOne();
			
			if (close == true)
			{
				closeMutex.ReleaseMutex();
#if LOG
				logger.Trace(String.Format(Catalog.GetString("Closing notify window: {0}"), name));
#endif
				evt.Skip();
				return;
			}
			else
			{
				close = true;
				closeMutex.ReleaseMutex();
			}	
			
		}
		
		private void FrameCloseAsyncRequest(object sender, wx.Event evt)
		{
			this.Close();
		}
		
		/// <summary>
		/// Window will stay open as long as this method is working
		/// </summary>
		private void LifeCycle()
		{
			int interval = 100;

			for (int time = 0; time <= ttl; time += interval) 
			{
				closeMutex.WaitOne();

				if (close == true)
				{
					closeMutex.ReleaseMutex();
					// we cant call this.Close() form here directly because we are in 
					// child thread, insted we must use UPDATE_UI event to do that
					this.EventHandler.AddPendingEvent(new wx.UpdateUIEvent((int) FakeId.closeNewChatNotify));
					return;
				}
				else
				{
					closeMutex.ReleaseMutex();
					System.Threading.Thread.Sleep(interval);
				}		
			}		
			
			closeMutex.WaitOne();
			{
				close = true;
			}
			closeMutex.ReleaseMutex();
			// we cant call this.Close() form here directly because we are in 
			// child thread, insted we must use UPDATE_UI event to do that for us
			this.EventHandler.AddPendingEvent(new wx.UpdateUIEvent((int) FakeId.closeNewChatNotify));
			
		}
	}
}
